package com.lzy.cloud.order.facade;

import com.github.pagehelper.PageInfo;
import com.lzy.cloud.order.constants.*;
import com.lzy.cloud.order.dtos.*;
import com.lzy.cloud.order.remote.CouponApi;
import com.lzy.cloud.order.remote.GoodsApi;
import com.lzy.cloud.order.remote.RabbitmqApi;
import com.lzy.cloud.order.remote.dtos.BaseCouponDto;
import com.lzy.cloud.order.remote.request.CarCalendarRequest;
import com.lzy.cloud.order.remote.response.BaseCouponResponse;
import com.lzy.cloud.order.service.*;
import com.lzy.cloud.order.utils.RuleUtil;
import com.lzy.framework.core.ensure.Ensure;
import com.lzy.framework.core.exceptions.XBusinessException;
import com.lzy.framework.core.lock.RedisGlobalLock;
import com.lzy.framework.core.orm.db.Pager;
import com.lzy.framework.core.utils.DateUtil;
import com.lzy.framework.core.utils.DozerUtils;
import com.lzy.framework.core.utils.StringUtil;
import com.lzy.framework.tools.commons.BigDecimalUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Description: 订单退换货退款业务
 * @Author:   gyl
 * @Date:     2018/7/10 20:55
 */
@Component
@Slf4j
public class OrderRefundFacade {

    @Autowired
    private OrderRefundService orderRefundService;

    @Autowired
    private OrderRefundLogService orderRefundLogService;

    @Autowired
    private OrderRefundMoneyService orderRefundMoneyService;

    @Autowired
    private OrderInfoCarRentService orderInfoCarRentService;

    @Autowired
    private OrderRefundPicService orderRefundPicService;

    @Autowired
    private OrderRefundVerifyService orderRefundVerifyService;

    @Autowired
    private OrderInfoService orderInfoService;

    @Autowired
    private RedisGlobalLock redisGlobalLock;

    @Autowired
    private OrderInfoFacade orderInfoFacade;

    @Autowired
    private OrderRuleService orderRuleService;

    @Autowired
    private OrderExpenseItemService orderExpenseItemService;

    @Autowired
    private RabbitmqApi rabbitmqApi;

    @Autowired
    private GoodsApi goodsApi;

    @Autowired
    private CouponApi couponApi;

    @Autowired
    private OrderCouponLogService orderCouponLogService;

    /**
     * 方法说明：查询展示列表
     * @date   2018/7/11 9:38
     */
    public PageInfo<OrderRefundDto> queryList(Pager pager, OrderRefundDto orderRefundDto){
        return orderRefundService.queryList(pager, orderRefundDto);
    }

    /**
     * 方法说明：根据订单号查找详情
     * @date   2018/7/11 9:38
     */
    public OrderRefundDto find(String orderId){
        OrderRefundDto orderRefundDto = orderRefundService.queryListByOrderId(orderId);
        if (orderRefundDto != null) {
            //退换货金额明细
            OrderRefundMoneyDto orderRefundMoneyDto = new OrderRefundMoneyDto();
            orderRefundMoneyDto.setOrderId(orderId);
            List<OrderRefundMoneyDto> moneyDtoList = orderRefundMoneyService.queryList(orderRefundMoneyDto);
            if (moneyDtoList != null) {
                orderRefundDto.setMoneyDtoList(moneyDtoList);
            }
            //退换货图片记录
            OrderRefundPicDto orderRefundPicDto = new OrderRefundPicDto();
            orderRefundPicDto.setOrderId(orderId);
            List<OrderRefundPicDto> picDtoList = orderRefundPicService.queryList(orderRefundPicDto);
            if (picDtoList != null) {
                orderRefundDto.setPicDtoList(picDtoList);
            }
            //退换货审核记录
            OrderRefundVerifyDto orderRefundVerifyDto = new OrderRefundVerifyDto();
            orderRefundVerifyDto.setOrderId(orderId);
            List<OrderRefundVerifyDto> verifyDtoList = orderRefundVerifyService.queryList(orderRefundVerifyDto);
            if (verifyDtoList != null) {
                orderRefundDto.setVerifyDtoList(verifyDtoList);
            }
        }
        return orderRefundDto;
    }

    /**
     * 方法说明：创建退换货相关
     * @date   2018/7/11 9:47
     */
    public Long create(OrderRefundDto orderRefundDto){
        //订单退换货主信息新增
        Long refundId = orderRefundService.create(orderRefundDto);
        Ensure.that(refundId).isGt(0, "00140001");

        //附属信息新增
        orderRefundDto.setId(refundId);
        createOrderRefundSub(orderRefundDto);
        return refundId;
    }

    /**
     * 方法说明：更新退换货相关
     * @date   2018/7/11 10:36
     */
    public Boolean update(OrderRefundDto orderRefundDto){
        //订单退换货主信息更新
        Boolean ok = orderRefundService.update(orderRefundDto);
        Ensure.that(ok).isTrue("00140006");

        //附属信息删除
        orderRefundMoneyService.deleteByRefundId(orderRefundDto.getId());
        orderRefundPicService.deleteByRefundId(orderRefundDto.getId());
        orderRefundVerifyService.deleteByRefundId(orderRefundDto.getId());

        //附属信息新增
        createOrderRefundSub(orderRefundDto);

        return Boolean.TRUE;
    }

    /**
     * 方法说明：订单退换货附属信息新增
     * @date   2018/7/11 12:03
     */
    private void createOrderRefundSub(OrderRefundDto orderRefundDto) {
        Long refundId = orderRefundDto.getId();
        //退换货金额明细
        List<OrderRefundMoneyDto> moneyDtoList = orderRefundDto.getMoneyDtoList();
        for (OrderRefundMoneyDto moneyDto : moneyDtoList) {
            if (moneyDto.getType()!=null && moneyDto.getType().equals(CommonConstants.OrderRefundMoneyType.ONLINE)) {
                OrderRefundLogDto orderRefundLogDto = DozerUtils.map(moneyDto, OrderRefundLogDto.class);
                orderRefundLogDto.setGoodsId(orderRefundDto.getGoodsId());
                Long logId = orderRefundLogService.create(orderRefundLogDto);
                Ensure.that(logId).isGt(0, "00140002");
            }
            moneyDto.setRefundId(refundId);
            Long moneyId = orderRefundMoneyService.create(moneyDto);
            Ensure.that(moneyId).isGt(0, "00140003");
        }
        //退换货图片记录
        List<OrderRefundPicDto> picDtoList = orderRefundDto.getPicDtoList();
        for (OrderRefundPicDto picDto : picDtoList) {
            picDto.setRefundId(refundId);
            Long picId = orderRefundPicService.create(picDto);
            Ensure.that(picId).isGt(0, "00140004");
        }
        //退换货审核记录
        List<OrderRefundVerifyDto> verifyDtoList = orderRefundDto.getVerifyDtoList();
        for (OrderRefundVerifyDto verifyDto : verifyDtoList) {
            verifyDto.setRefundId(refundId);
            Long verifyId = orderRefundVerifyService.create(verifyDto);
            Ensure.that(verifyId).isGt(0, "00140006");
        }
    }

    /**
     * 逻辑退订
     *
     * @param refundMoneyDTO
     * @return
     */
    public void exeLogicRefund(RefundMoneyDto refundMoneyDTO) {
        OrderInfoDto oid = orderInfoService.find(refundMoneyDTO.getOrderId());
        switch (oid.getType() + "") {
            case CommonConstants.Biz.TOUR_CAR_SALE:
                Ensure.that(true).isFalse("08000001");
                break;
            case CommonConstants.Biz.TOUR_CAR_RENT:
                recoverTourCarRentStock(oid);
                exeCarRent(refundMoneyDTO, oid);
                // 通知保险退订
//                insuOrderServiceApi.updateTypeById(sor.getOrderId(), 3);
        }
    }

    // 释放房车的档期
    private void recoverTourCarRentStock(OrderInfoDto orderInfoDto) {
        OrderInfoCarRentDto oicDto = orderInfoCarRentService.queryByOrderId(orderInfoDto.getOrderId());
        if(oicDto != null && !StringUtil.isNotEmpty(oicDto.getStartDate()) && !StringUtil.isNotEmpty(oicDto.getEndDate())){
            CarCalendarRequest carCalendarRequest = new CarCalendarRequest();
            carCalendarRequest.setCarId(oicDto.getCarId());
            carCalendarRequest.setStartDate(oicDto.getStartDate());
            carCalendarRequest.setEndDate(oicDto.getEndDate());
            Boolean ok = DozerUtils.map(goodsApi.releaseCalendar(carCalendarRequest).getResult(),Boolean.class);
            Ensure.that(ok).isTrue("01000006");
        }
    }

        private void exeCarRent(RefundMoneyDto refundMoneyDTO, OrderInfoDto oid) {
            String key = OrderDistributePrefix.ORDER_ID + oid.getOrderId();
            if (redisGlobalLock.lock(key, 3000, TimeUnit.MILLISECONDS)) {
                 try {
                     // 判断是否执行过
                     Ensure.that(oid.getMinStatus().equals(OrderStatusDesEnum.TOURCARRENT_NO_GOODS.getStatus()))
                             .isTrue("08000011");
                     BaseOrderDto bod = orderInfoFacade.find(refundMoneyDTO.getOrderId());
        //                        String count = RuleUtil.CarRentRefundRule(bod.getOrderInfoCarRentDto().getStartDate());
                     String count = RuleUtil.CarRentRefundRule(DateUtil.parse(bod.getOrderInfoCarRentDto().getStartDate(), "yyyy-MM-dd hh:mm:ss"));
                     List<OrderExpenseItemDto> orderExpenseItemDtoList = orderExpenseItemService.queryListByOrderId(refundMoneyDTO.getOrderId());
                     //余额抵扣金额
                     BigDecimal balancePaid = new BigDecimal(0);
                     //在线支付金额
                     BigDecimal onlinePaid = new BigDecimal(0);
                     //订单支付总额（余额支付 + 在线支付）
                     BigDecimal allPaid = new BigDecimal(0);
                     //订单应退总额
                     BigDecimal returnMoney = new BigDecimal(0);
                     if(orderExpenseItemDtoList != null && orderExpenseItemDtoList.size() > 0){
                         for (OrderExpenseItemDto oeiDto:orderExpenseItemDtoList) {
                             if(oeiDto.getType().equals(OrderBusiConstants.OrderExpenseItemEnum.BALANCE_DEDUCTION)){
                                 balancePaid = oeiDto.getAmount();
                             }
                             if(oeiDto.getType().equals(OrderBusiConstants.OrderExpenseItemEnum.ONLINE_PAYMENT)){
                                 onlinePaid = oeiDto.getAmount();
                             }
                         }
                         allPaid = balancePaid.add(onlinePaid);
                     }

                     //订单中的卡券id列表
                     List couponIdList = new ArrayList();
                     //订单中的应退卡券id列表
                     List<Long> returnCouponList = new ArrayList();
                     //计算应退余额（先退在线支付，再退余额支付,保险费用不退，房车券四舍五入退，房车代金券不退）
                     //订单对应的退订规则
                     OrderRuleDto orderRuleDto = orderRuleService.queryByOrderId(refundMoneyDTO.getOrderId());
                     if (orderRuleDto != null && !StringUtil.isNotEmpty(orderRuleDto.getRuleDetail())){
                         //计算应退卡券
                         //查找该订单共用卡券数
                         OrderCouponLogDto oclDto = new OrderCouponLogDto();
                         oclDto.setMemberId(oid.getMemberId());
                         oclDto.setOrderId(oid.getOrderId());
                         oclDto.setType(CommonConstants.OrderCouponLogType.USER_CONSUME);
                         List<OrderCouponLogDto> orderCouponLogDtoList = orderCouponLogService.selectList(oclDto);
                         //订单所用卡券数量
                         Integer couponNum = 0;
                         //订单退订卡券数量
                         Integer returnCoupon = 0;
                         if(orderCouponLogDtoList != null && orderCouponLogDtoList.size() > 0){
                             for (OrderCouponLogDto orderCouponLog:orderCouponLogDtoList) {
                                 couponIdList.add(orderCouponLog.getCouponId());
                             }
                         }
                         String[] rules = orderRuleDto.getRuleDetail().split("|");
                         //第一个数字是24小时之内退款需退订的百分数
                         //第二个数字是24小时至72小时之内退款需退订的百分数
                         //第三个数字是72小时之外退款需退订的百分数
                         switch (count){
                             case BizRuleConstants.CarRentRule.CarRentStage.FIRST:
                                 //说明不退款
                                if (rules[0].equals("0")){
                                    Ensure.that(true).isFalse("00140007");
                                }else{
                                    BigDecimal ratio = BigDecimal.valueOf(Double.valueOf(rules[0])).divide(new BigDecimal(100));
                                    //退款
                                    returnMoney = BigDecimalUtil.to2Point(
                                            BigDecimalUtil.multiply(allPaid, ratio));
                                    //卡券
                                    returnCouponList = calculateReturnCoupon(rules[0],couponIdList);
                                }
                                break;
                             case BizRuleConstants.CarRentRule.CarRentStage.SENCOND:
                                 //说明不退款
                                 if (rules[1].equals("0")){
                                     Ensure.that(true).isFalse("00140008");
                                 }else{
                                     BigDecimal ratio = BigDecimal.valueOf(Double.valueOf(rules[1])).divide(new BigDecimal(100));
                                     //退款
                                     returnMoney = BigDecimalUtil.to2Point(
                                             BigDecimalUtil.multiply(allPaid, ratio));
                                     //卡券
                                     returnCouponList = calculateReturnCoupon(rules[1],couponIdList);
                                 }
                                 break;
                             case BizRuleConstants.CarRentRule.CarRentStage.THIRD:
                                 //说明不退款
                                 if (rules[2].equals("0")){
                                     Ensure.that(true).isFalse("00140009");
                                 }else{
                                     BigDecimal ratio = BigDecimal.valueOf(Double.valueOf(rules[2])).divide(new BigDecimal(100));
                                     //退款
                                     returnMoney = BigDecimalUtil.to2Point(
                                             BigDecimalUtil.multiply(allPaid, ratio));
                                     //卡券
                                     returnCouponList = calculateReturnCoupon(rules[2],couponIdList);
                                 }
                         }
                     }
                     MsgOrderRefundDto msgOrderRefundDto = new MsgOrderRefundDto();
                     msgOrderRefundDto.setOrderId(oid.getOrderId());
                     msgOrderRefundDto.setReturnAllMoney(returnMoney);
                     msgOrderRefundDto.setMemberId(oid.getMemberId());
                     msgOrderRefundDto.setShopId(oid.getShopId());
                     //判断退款类型（先退在线支付，再退余额支付）
                     //退款金额不能为0
                     if(!BigDecimalUtil.isZeroOrNull(returnMoney)){
                         //比较returnMonty和onlinePaid的大小关系
                         if(returnMoney.compareTo(onlinePaid)<=0){
                             //在线支付上退returnMoney
                             msgOrderRefundDto.setReturnOnline(returnMoney);
                         }else{
                             BigDecimal returnBalance = returnMoney.subtract(onlinePaid);
                             //在线支付上退onlinePaid,余额支付上退returnBalance
                             msgOrderRefundDto.setReturnOnline(onlinePaid);
                             msgOrderRefundDto.setReturnBalance(returnBalance);
                         }
                     }

                     //更新订单状态为已退款
                     OrderInfoDto orderInfoDto = new OrderInfoDto();
                     orderInfoDto.setOrderId(oid.getOrderId());
                     if(BigDecimalUtil.isZeroOrNull(returnMoney)){
                         orderInfoDto.setMaxStatus(CommonConstants.OrderBigStatus.OVER_ORDER);
                         orderInfoDto.setMinStatus(OrderStatusDesEnum.TOURCARRENT_PAYED.getStatus());
                         orderInfoDto.setDesStatus(OrderStatusDesEnum.TOURCARRENT_PAYED.getDes());
                     }else{
                         orderInfoDto.setMaxStatus(CommonConstants.OrderBigStatus.BACK_ORDER);
                         orderInfoDto.setMinStatus(OrderStatusDesEnum.TOURCARRENT_PAYING.getStatus());
                         orderInfoDto.setDesStatus(OrderStatusDesEnum.TOURCARRENT_PAYING.getDes());
                     }
                     orderInfoService.update(orderInfoDto);
                     //添加rabbitMQ实时队列（在线支付退款，余额支付退款）
                     rabbitmqApi.unsubscribe(msgOrderRefundDto);
                     //房车券退回
                     //先将returnCouponList里的卡券状态改为已绑定
                     BaseCouponDto baseCouponDto = new BaseCouponDto();
                     baseCouponDto.setStatus(OrderBusiConstants.CouponStatus.BIND.getCode());
                     String couponIdStr = "";
                     for (Long id:returnCouponList) {
                         baseCouponDto.setId(baseCouponDto.getId());
                         couponApi.update(baseCouponDto);
                         couponIdStr = couponIdStr + ",";
                     }
                     //订单中券流向记录更改
                     OrderCouponLogDto couponLogDto = new OrderCouponLogDto();
                     couponLogDto.setOrderId(oid.getOrderId());
                     couponLogDto.setMemberId(oid.getMemberId());
                     couponLogDto.setType(CommonConstants.OrderCouponLogType.SYSTEM_RETURN);
                     orderCouponLogService.updateManyLog(couponLogDto,couponIdStr.substring(0,couponIdStr.length() - 1));
                     //order_refund表添加退款信息
                     OrderRefundDto orderRefundDto = new OrderRefundDto();
                     orderRefundDto.setOrderId(oid.getOrderId());
                     orderRefundDto.setMemberId(oid.getMemberId());
                     orderRefundDto.setOrderInfoType(OrderBusiConstants.OrderTypeEnum.TOURCARRENT.getType());
                     //根据orderId获取房车租赁订单子表的信息
                     OrderInfoCarRentDto oicrDto = orderInfoCarRentService.queryByOrderId(oid.getOrderId());
                     if(oicrDto != null && oicrDto.getCarId() != null){
                         orderRefundDto.setGoodsId(oicrDto.getCarId());
                     }
                     orderRefundDto.setShopId(oid.getShopId());
                     orderRefundDto.setShopName(oid.getShopName());
                     orderRefundDto.setType(OrderBusiConstants.RefundEnum.MONEY.getK());
                     Long refundId = orderRefundService.create(orderRefundDto);
                     //order_refund_log表添加订单退款记录
                     OrderRefundLogDto orderRefundLogDto = new OrderRefundLogDto();
                     orderRefundLogDto.setMemberId(oid.getMemberId());
                     orderRefundLogDto.setGoodsId(orderRefundDto.getGoodsId());
                     orderRefundLogDto.setOrderId(oid.getOrderId());
                     orderRefundLogDto.setRefundId(refundId);
                     orderRefundLogDto.setMoney(returnMoney);
                     orderRefundLogService.create(orderRefundLogDto);
                     //order_refund_money表添加订单退款金额明细
                     OrderRefundMoneyDto orderRefundMoneyDto = new OrderRefundMoneyDto();
                     orderRefundMoneyDto.setOrderId(oid.getOrderId());
                     orderRefundMoneyDto.setRefundId(refundId);
                     orderRefundMoneyDto.setMemberId(oid.getMemberId());
                     //在线支付退款
                     if(!BigDecimalUtil.isZeroOrNull(msgOrderRefundDto.getReturnOnline())){
                         orderRefundMoneyDto.setType(2);
                         orderRefundMoneyDto.setTypeValue(msgOrderRefundDto.getReturnOnline());
                         orderRefundMoneyService.create(orderRefundMoneyDto);
                     }
                     //余额支付退款
                     if(!BigDecimalUtil.isZeroOrNull(msgOrderRefundDto.getReturnBalance())){
                         orderRefundMoneyDto.setType(3);
                         orderRefundMoneyDto.setTypeValue(msgOrderRefundDto.getReturnBalance());
                         orderRefundMoneyService.create(orderRefundMoneyDto);
                     }
                     //退款总额
                     if(!BigDecimalUtil.isZeroOrNull(msgOrderRefundDto.getReturnAllMoney())){
                         orderRefundMoneyDto.setType(1);
                         orderRefundMoneyDto.setTypeValue(msgOrderRefundDto.getReturnAllMoney());
                         orderRefundMoneyService.create(orderRefundMoneyDto);
                     }
                 } catch (XBusinessException e) {
                         throw e;
                     } finally {
                         redisGlobalLock.unlock(key);
                     }
                }
         }

    /**
     * 计算应退房车券张数及退哪几张房车券（房车券张数：四舍五入；房车券哪几张：退过期时间较久的）
     * @param rules
     * @param couponIdList
     * @return
     */
         public List calculateReturnCoupon(String rules,List<Long> couponIdList) {
             List returnCouponList = null;
             if (couponIdList.size() > 0) {
                 BigDecimal returnCouponNum = (new BigDecimal(couponIdList.size()).multiply(BigDecimal.valueOf(Double.valueOf(rules)).divide(new BigDecimal(100)))).setScale(0, BigDecimal.ROUND_HALF_UP);
                 //应退回房车券张数
                 Integer returnCoupon = returnCouponNum.intValue();
                 if(returnCoupon > 0){
                     List<BaseCouponResponse> couponResponseList = DozerUtils.maps((List)couponApi.findCarRentByIds(couponIdList).getResult(),BaseCouponResponse.class);
                     if(couponResponseList != null && couponResponseList.size() > 0){
                         HashMap mapCoupon = new HashMap();
                         for (BaseCouponResponse couponResponse:couponResponseList) {
                             if(couponResponse != null && StringUtil.isNotEmpty(couponResponse.getExpiryTime())){
                                 mapCoupon.put(couponResponse.getId(),couponResponse.getExpiryTime());
                             }
                         }
                         List<Map.Entry<Integer, String>> mapReturnCoupon = new ArrayList<Map.Entry<Integer, String>>(mapCoupon.entrySet());
                         Collections.sort(mapReturnCoupon, new Comparator<Map.Entry<Integer, String>>() {
                             public int compare(Map.Entry<Integer, String> o1, Map.Entry<Integer, String> o2) {
                                 //o1 to o2升序   o2 to o1降序
                                 return o2.getValue().compareTo(o1.getValue());
                             }
                         });
                         for(int i=0;i<returnCoupon;i++){
                             System.out.println(mapReturnCoupon.get(i).getKey());
                             returnCouponList.add(mapReturnCoupon.get(i).getKey());
                         }
                     }
                 }
             }
             return returnCouponList;
         }


}
